// 保证jQuery与其它javascript lib的兼容性
//if($j == null) {
	$j = jQuery.noConflict();
//}


/*
**********************************
	表单数据绑定规范:
**********************************
	1. JSONRPC<---->java类型转换，参见jabsorb/json-rpc-java
	2. 属性对象嵌套属性计算符号：由全局变量 NESTPROPERTYSEPERATOR 定义，缺省为"-"（可自定义），例如：可用"a-b"来绑定属性a对象的b嵌套属性
	3. 类型元数据：{
			type: "boolean/number/string/date/array/map/list/object",
			javaClass: java类型全名,
			element: 类型元数据

			属性名称1: 类型元数据
			属性名称n: 类型元数据
		}

		其中:
			boolean/number/string/array为基本类型，可以不指定javaClass，jabsorb会推测出来
			date/map/list/object为复杂类型，应指定javaClass
				date类型的javaClass缺省为java.util.Date
				map类型的javaClass缺省为java.util.HashMap
				list类型的javaClass缺省为java.util.ArrayList
				顶层对象类型为object时，javaClass可以不指定，jabsorb会推测出来
			array/map/list为集合类型，应指定成员的类型元数据element
	4. dc:grid组件绑定MAP类型（很少用）： 绑定MAP的key采用虚拟列名MAPKEYNAME，缺省为"map[key]"（可自定义）；其它值直接绑定到MAP值对象的嵌套属性
*/


//组件name/id中嵌套属性分隔符
var NESTPROPERTYSEPERATOR = "-";
//dc:grid绑定MAP类型的键值虚拟列名称
var MAPKEYNAME = "map[key]";

//元数据
var DATABINDINGMETADATA = {};

/**
 * 添加java类的元数据
 */
function addClassMetaData(javaClass, metaData){
	if(DATABINDINGMETADATA[javaClass] == null) {
		var bCompleteClassDesc = false;
		//添加嵌套类型描述到顶级
		for(var propName in metaData) {
			bCompleteClassDesc = bCompleteClassDesc || (propName != "type") && (propName != "javaClass");
			if((propName != "type") && (propName != "javaClass")){
				var innerMetaData = metaData[propName];
				if((innerMetaData != null) && (innerMetaData.javaClass != null)){
					addClassMetaData(innerMetaData.javaClass, innerMetaData);
				}
			}
		}

		if((metaData.javaClass==null) && (addClassMetaData.caller!=addClassMetaData)){
			metaData.javaClass = javaClass;
			bCompleteClassDesc = true;
		}

		if(bCompleteClassDesc && (metaData.javaClass != null)) {
			DATABINDINGMETADATA[javaClass] = metaData;
		}
	}
}

/**
 * 获取java类的元数据
 */
function getClassMetaData(javaClass){
	if(javaClass == null){
		return null;
	}
	else{
		return DATABINDINGMETADATA[javaClass];
	}
}


/**
 * 获取java类的属性的元数据
 */
function getPropertyClassMetaData(javaClass, propertyName) {
	var javaClassMetaData = getClassMetaData(javaClass);

	var arrayNestPropertyName = propertyName.split(NESTPROPERTYSEPERATOR);
	while(arrayNestPropertyName.length > 0){
		var nestPropertyName = arrayNestPropertyName.shift();
		//get nest object property metadata
		if(javaClassMetaData != null){
			javaClassMetaData = javaClassMetaData[nestPropertyName];
			javaClass = (javaClassMetaData != null)? javaClassMetaData.javaClass: null;
			var refJavaClassMetaData = getClassMetaData(javaClass);
			if(refJavaClassMetaData != null) {
				javaClassMetaData = refJavaClassMetaData;
			}
		}
	}

	return javaClassMetaData;
}


/*
 * 清空表单
 */
function clearForm(formID) {

	//清除特殊组件的值
	$j((formID? "#" + formID: "form") + " div[type='select'],div[type='xtree']").each(function(){
		//下拉框、下拉树
		this.faces.clearValue();
	});
	$j((formID? "#" + formID: "form") + " div[type='grid']").each(function(){
		//表格
		this.faces.clearAll(false);
	});

	var inputNameFormPrefix = formID? formID+":": "";
	$j((formID? "#" + formID: "form") + " input[type!='button'][type!='submit'][name!=''],textArea[name!='']").each(function(){
		var propertyName = this.name;
		if((inputNameFormPrefix != "") && (propertyName.indexOf(inputNameFormPrefix)==0)) {
			propertyName = propertyName.substr(inputNameFormPrefix.length);
		}

		//ignore iceface message
		if(propertyName.match( /javax\..*/ )) return;
		if(propertyName.match( /iceface.*/ )) return;
		if(propertyName.match( /j_id.*/ )) return;
		if(propertyName.match( /_id.*/ )) return;
		if(propertyName.match( /.*_cb/ )) return;

		if(this.type == "checkbox"){
			this.checked=false;
		} else {
				if(this.type == "radio"){
				} else {
  				this.value="";
				}
  	}
	});
}


/*
 * 从表单提取JSON对象
 */
function form2Bean(formID, javaClass) {
	var formBean = {};
	var inputNameFormPrefix = formID? formID+":": "";

	$j((formID? "#" + formID: "form") + " input[type!='button'][type!='submit'][name!=''],textArea[name!='']").each(function(){
		var propertyName = this.name;
		//排除ice:form的隐藏字段
		if((formID != null) && (formID == propertyName)){
			return;
		}

		if((inputNameFormPrefix != "") && (propertyName.indexOf(inputNameFormPrefix)==0)) {
			propertyName = propertyName.substr(inputNameFormPrefix.length);
		}

		//ignore iceface message
		if(propertyName.match( /javax\..*/ )) return;
		if(propertyName.match( /iceface.*/ )) return;
		if(propertyName.match( /j_id.*/ )) return;
		if(propertyName.match( /_id.*/ )) return;
		if(propertyName.match( /.*_cb/ )) return;

		var propertyValue="";
		if(this.type=="checkbox"){
			propertyValue = this.checked;
		}else{
			if(this.type=="radio" && this.checked==true){
				propertyValue = this.value;
			}else{
				 propertyValue = this.value;
			}
		}
  	setBeanProperty(formBean, propertyName, propertyValue, javaClass);
	});

	//获取特殊组件的值
	$j((formID? "#" + formID: "form") + " div[type='select'],div[type='xtree']").each(function(){
		//下拉框、下拉树
		var propertyName = this.id;
		if(propertyName != null){
			if((inputNameFormPrefix != "") && (propertyName.indexOf(inputNameFormPrefix)==0)) {
				propertyName = propertyName.substr(inputNameFormPrefix.length);
			}
  			setBeanProperty(formBean, propertyName, this.faces.getValue(), javaClass);
		}
	});
	$j((formID? "#" + formID: "form") + " div[type='grid']").each(function(){
		//表格
		var propertyName = this.id;
		if(propertyName != null){
			if((inputNameFormPrefix != "") && (propertyName.indexOf(inputNameFormPrefix)==0)) {
				propertyName = propertyName.substr(inputNameFormPrefix.length);
			}
			//get element class metadata
			var javaClassMetaData = getPropertyClassMetaData(javaClass, propertyName);
			var elementJavaClassMetaData = (javaClassMetaData != null)? javaClassMetaData.element: null;
			var elementJavaClass = (elementJavaClassMetaData != null)? elementJavaClassMetaData.javaClass: null;

			var propertyValue = [];
			var mapBinding = false;
			if(javaClassMetaData != null){
				mapBinding = (javaClassMetaData.type == "map");
			}
			else{
				var columnNames = this.faces.column.names;
				for(var i=0; i < columnNames.length; i++){
					var columnName = columnNames[i];
					if(columnName == MAPKEYNAME){
						mapBinding = true;
						break;
					}
				}
			}
			if(mapBinding){
				//MAP需要特殊处理
				propertyValue = {};
				var rowCount = this.faces.getRowsNum();
				for(var rowIndex = 0; rowIndex < rowCount; rowIndex++){
					var row = {};
					var key = null;
					if( (this.faces.column != null) && (this.faces.column.names != null) ) {
						var columnNames = this.faces.column.names;
						for(var i=0; i < columnNames.length; i++){
							var columnName = columnNames[i];
							var columnIndex = this.faces.getColumnIndex(columnName);
							if(columnIndex >= 0){
								var columnValue = this.faces.cells2(rowIndex, columnIndex).getValue();
								if(columnName == MAPKEYNAME){
									key = columnValue;
								}
								else{
	  								setBeanProperty(row, columnName, columnValue, elementJavaClass);
	  							}
							}
						}
					}
					if(key != null) {
						propertyValue[key] = row;
					}
					else{
						throw "dc:grid绑定到map，必须指定" + MAPKEYNAME + "作为键值列！";
					}
				}
			}
			else{
				propertyValue = [];
				var rowCount = this.faces.getRowsNum();
				for(var rowIndex = 0; rowIndex < rowCount; rowIndex++){
					var row = {};
					if( (this.faces.column != null) && (this.faces.column.names != null) ) {
						var columnNames = this.faces.column.names;
						for(var i=0; i < columnNames.length; i++){
							var columnName = columnNames[i];
							var columnIndex = this.faces.getColumnIndex(columnName);
							if(columnIndex >= 0){
	  							setBeanProperty(row, columnName, this.faces.cells2(rowIndex, columnIndex).getValue(), elementJavaClass);
							}
						}
					}
					propertyValue.push(row);
				}
			}

  			setBeanProperty(formBean, propertyName, propertyValue, javaClass);
		}
	});

	return formBean;
}

/*
 * 把JSON对象提交到表单
 */
function bean2Form(formID, bean, propertyNamePrefix) {
	var inputNameFormPrefix = formID? formID+":": "";
	var inputNameNestPrefix = propertyNamePrefix? propertyNamePrefix + NESTPROPERTYSEPERATOR: "";
	for (propertyName in bean) {
		var propertyValue = getBeanProperty(bean, propertyName);
		var propertyType = typeof propertyValue;
		if(propertyType != "function"){
			if((propertyValue != null) && (propertyType == "object")){
				bean2Form(formID, propertyValue, inputNameNestPrefix + propertyName);
			}
			else {
				var inputName = inputNameFormPrefix + inputNameNestPrefix + propertyName;
				$j((formID? "#" + formID: "form") + " input[name='" + inputName + "'],textArea[name='" + inputName + "']").each(function(){
					if(this.type == "checkbox") {
						this.checked = Boolean(propertyValue).valueOf();
					}
					else{
						if(this.type == "radio") {
							this.checked = (this.value==propertyValue);
						}
						else{
							this.value = (propertyValue==null)? "": propertyValue;
						}
					}
				});
			}
		}
	}

	//设置特殊组件的值
	if(bean2Form.caller != bean2Form) {
		$j((formID? "#" + formID: "form") + " div[type='select'],div[type='xtree']").each(function(){
			//下拉框、下拉树
			var propertyName = this.id;
			if(propertyName != null){
				debugger;
				if((inputNameFormPrefix != "") && (propertyName.indexOf(inputNameFormPrefix)==0)) {
					propertyName = propertyName.substr(inputNameFormPrefix.length);
				}
				var propertyValue = getBeanProperty(bean, propertyName);
				propertyValue = propertyValue!=null? propertyValue: "";
				this.faces.setValue(propertyValue);
			}
		});
		$j((formID? "#" + formID: "form") + " div[type='grid']").each(function(){
			//表格
			var propertyName = this.id;
			if(propertyName != null){
				debugger;
				if((inputNameFormPrefix != "") && (propertyName.indexOf(inputNameFormPrefix)==0)) {
					propertyName = propertyName.substr(inputNameFormPrefix.length);
				}

				this.faces.clearAll(false);
				var propertyValue = getBeanProperty(bean, propertyName);
				if(propertyValue != null) {
					if(!$j.isArray(propertyValue)){
						//MAP, 需要转换为数组，并虚构一个map[key]列作为键值
						var map = propertyValue;
						propertyValue = [];
						for(var key in map){
							var item = {};
							item[MAPKEYNAME] = key;
							var obj = map[key];
							for(var prop in obj){
								item[prop] = obj[prop];
							}
							propertyValue.push(item);
						}
					}

					for(var rowIndex = 0; rowIndex < propertyValue.length; rowIndex++){
						this.faces.appendClick()
						var row = propertyValue[rowIndex];
						for(columnName in row){
							var columnIndex = this.faces.getColumnIndex(columnName);
							if(columnIndex >= 0){
								this.faces.cells2(rowIndex, columnIndex).setValue(row[columnName]);
							}
						}
					}
				}
			}
		});
	}
}


/*
 * 为对象设置属性
 */
function setBeanProperty(bean, propertyName, propertyValue, javaClass) {
	if((bean != null) && (javaClass != null)&& (bean.javaClass == null)){
		bean.javaClass = javaClass;
	}
	var javaClassMetaData = getClassMetaData(javaClass);
	var arrayNestPropertyName = propertyName.split(NESTPROPERTYSEPERATOR);
	if(arrayNestPropertyName.length > 0){
		while(arrayNestPropertyName.length > 0){
			var nestPropertyName = arrayNestPropertyName.shift();
	  		//get nest object property metadata
	  		if(javaClassMetaData != null){
	  			javaClassMetaData = javaClassMetaData[nestPropertyName];
	  			javaClass = (javaClassMetaData != null)? javaClassMetaData.javaClass: null;
				var refJavaClassMetaData = getClassMetaData(javaClass);
				if(refJavaClassMetaData != null) {
					javaClassMetaData = refJavaClassMetaData;
				}
	  		}

			if(arrayNestPropertyName.length > 0) {
				//nest object property
				var beanContainer = bean;
	  			bean = beanContainer[nestPropertyName];
	  			if(bean == null){
	  				bean = {};
					if(javaClass != null){
						bean.javaClass = javaClass;
					}
	  				beanContainer[nestPropertyName] = bean;
	  			}
	  		}
	  		else{
				//simple property
				propertyValue = javascriptObject2TypedJSON(propertyValue, javaClass, javaClassMetaData);
				bean[nestPropertyName] = propertyValue;
	  		}
		}
	}
}

/*
 * 从对象中取属性
 */
function getBeanProperty(bean, propertyName) {
	var propertyValue = null;
  	var arrayNestPropertyName = propertyName.split(NESTPROPERTYSEPERATOR);
  	if(arrayNestPropertyName.length > 0){
  		while(arrayNestPropertyName.length > 0){
  			var nestPropertyName = arrayNestPropertyName.shift();
  			if(arrayNestPropertyName.length > 0) {
				//nest object property
				bean = typedJSON2JavascriptObject(bean[nestPropertyName]);
	  			if(bean == null){
	  				break;
	  			}
	  		}
	  		else{
				//simple property
  				propertyValue = typedJSON2JavascriptObject(bean[nestPropertyName]);
	  		}
  		}
  	}

  	return propertyValue;
}


/*
 * 从普通的javascript对象转换为带类型的JSON对象
 * @param jsObject javascript对象
 * @param javaClass java类型
 * @param javaClassMetaData Java类型元数据（可选）
 */
function javascriptObject2TypedJSON(jsObject, javaClass, javaClassMetaData){
	var value = jsObject;

	if(javaClassMetaData == null){
		javaClassMetaData = getClassMetaData(javaClass);
	}
	if(javaClassMetaData != null){
		switch(javaClassMetaData.type){
			case "boolean":
				value = ((jsObject==null)||(jsObject==""))? false: new Boolean(jsObject).valueOf();
				break;
			case "number":
				value = ((jsObject==null)||(jsObject==""))? 0: new Number(jsObject).valueOf();
				break;
			case "string":
				value = (jsObject==null)? null: new String(jsObject).valueOf();
				break;
			case "date":
				if(jsObject != null){
					value = string2Date(jsObject);
					value.javaClass = (javaClass!=null)? javaClass: "java.util.Date";
				}
				break;
			case "array":
				if(jsObject != null){
					value = _jsObjectList2TypedJSONList(jsObject, javaClassMetaData);
				}
				break;
			case "map":
				if(jsObject != null){
					value = {
						javaClass: (javaClass!=null)? javaClass: "java.util.HashMap",
						map: jsObject
						};
				}
				break;
			case "list":
				if(jsObject != null){
					var value = {
						javaClass: (javaClass!=null)? javaClass: "java.util.ArrayList",
						list: _jsObjectList2TypedJSONList(jsObject, javaClassMetaData)
						};
				}
				break;
			case "object": //default
			default:
				if((value != null) && (javaClass != null)){
					value.javaClass = javaClass;
				}
		}
	}

	return value;
}

function _jsObjectList2TypedJSONList(jsObject, javaClassMetaData){
	var value = jsObject;
	//get element class metadata
	var elementJavaClassMetaData = javaClassMetaData.element;
	var elementJavaClass = (elementJavaClassMetaData != null)? elementJavaClassMetaData.javaClass: null;
	var refElementJavaClassMetaData = getClassMetaData(elementJavaClass);
	if(refElementJavaClassMetaData != null) {
		elementJavaClassMetaData = refElementJavaClassMetaData;
	}

	if(!$j.isArray(jsObject)){
		value = [jsObject];
	}

	if(elementJavaClass != null) {
		for(var index=0; index<jsObject.length; index++){
			if(jsObject[index].javaClass == null){
				value[index].javaClass = elementJavaClass;
			}
		}
	}

	return value;
}

/*
 * 从带类型的JSON对象转换为普通的javascript对象
 */
function typedJSON2JavascriptObject(typedJSON) {
	var value = typedJSON;
	if(typedJSON != null) {
		var javascriptType = typeof typedJSON;
		if((javascriptType != "string") && (javascriptType != "number") && (javascriptType != "boolean") && (javascriptType != "date") && (javascriptType != "array")){
			var javaClass = typedJSON["javaClass"];
			if(javaClass != null) {
				switch(javaClass){
					case "java.util.Date":
					case "java.sql.Date":
						// 日期类型
						time = typedJSON["time"];
						if(time != null) {
							value = date2String(new Date(time));
						}
						break;
					case "java.sql.Time":
					case "java.sql.Timestamp":
						// 时间类型
						time = typedJSON["time"];
						if(time != null) {
							value = time2String(new Date(time));
						}
						break;
					case "java.util.ArrayList":
					case "java.util.LinkedList":
						// 列表类型
						value = typedJSON["list"];
						break;
					case "java.util.HashMap":
						// 字典类型
						value = typedJSON["map"];
						break;
				}
			}
		}
	}

  	return value;
}

function date2String(date) {
	return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
}

function time2String(date) {
	return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate() + " " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();
}

function string2Date(strDate) {
	var date = null;

	//格式: YYYY-/M[M]-/D[D] [h[h]:m[m]:s[s]]
	var strDate = strDate.replace(/(^\s+|\s+$)/g, "");
	var s = strDate.replace(/\d{4,4}[\-/]{1}\d{1,2}[\-/]{1}\d{1,2}(\s{1,}\d{1,2}:{1}\d{1,2}:{1}\d{1,2}){0,1}/g, "");
	if ( s== "")  {
		var arg = strDate.split(/[\s-/:]/);
		if(arg.length == 3) {
			date = new Date(parseInt(arg[0]), parseInt(arg[1])-1, parseInt(arg[2]));
		}
		else{
			date = new Date(parseInt(arg[0]), parseInt(arg[1])-1, parseInt(arg[2]), parseInt(arg[3]), parseInt(arg[4]), parseInt(arg[5]));
		}
	}
	 else{
	 	date = null;
	 }

	 return date;
}


function exceptionToString (e) {
	var str="";
	for(var a in e) {
		str+=a +"\t"+e[a]+"\n";
	}

  	return str;
};
